#include "Stack.h"
#include "neiderra/core/Types.h"

using namespace neiderra::vm;
using namespace neiderra::types;

Stack::Stack(unsigned size)
{
	_mem = new unsigned char[size];
	_top=0;
	_size = size;
}

Stack::~Stack()
{
	delete[] _mem;
}

int Stack::push(unsigned int size, nByte* var)
{
	if(_top+size >= _size)
	{
		//throw overflow();
		return 1;
	}
	
	for(unsigned i=0;i<size;i++,_top++)
	{
		_mem[_top]=var[i];
	}
	return 0;
}

int Stack::pop(int size, nByte* var)
{
	int res = _top-size;
	
	if( res < 0 )
		return 1;

	for(unsigned i=_top-size,j=0; i<_top;i++,j++)
	{
		var[j]=_mem[i];
	}
	return 0;
}

void Stack::set(unsigned ptr, unsigned size, nByte *var)
{
	if(ptr+size > _top) 
		throw overflow();

	for(unsigned i=0;i<size;i++)
		_mem[ptr+i]=var[i];
}

void Stack::set(unsigned ptr, unsigned value)
{
	set(ptr, 4, reinterpret_cast<nByte*>(&value));
}

void Stack::get(unsigned ptr, unsigned size, nByte* var)
{
	if(ptr+size > _top) 
		throw overflow();
	
	for(unsigned i=0;i<size;i++)
		var[i] = _mem[ptr+i];
}

unsigned Stack::getui(unsigned ptr)
{
	nByte res[4];
	get(ptr, 4, res);
	return *reinterpret_cast<unsigned*>(res);
}

signed Stack::geti(unsigned ptr)
{
	nByte res[4];
	get(ptr, 4, res);
	return *reinterpret_cast<signed*>(res);
}

void Stack::push(int x)
{
	push(sizeof(int), reinterpret_cast<nByte*>(&x));
}

void Stack::push(float x)
{
	push(sizeof(float), reinterpret_cast<nByte*>(&x));
}

void Stack::push(char x)
{
	push(sizeof(char), reinterpret_cast<nByte*>(&x));
}

int Stack::topi()
{
	nByte var[4];
	if(pop(4, var)) 
		throw underflow();
	return *reinterpret_cast<int*>(var);
}

int Stack::popi()
{
	nByte var[4];
	if(pop(4, var))
		throw underflow();
	_top-=4;
	return *reinterpret_cast<int*>(var);
}

float Stack::popf()
{
	nByte var[6];
	if(pop(6, var))
		throw underflow();
	_top-=6;
	return *reinterpret_cast<float*>(var);
}

char Stack::popc()
{
	nByte var[1];
	if(pop(1, var))
		throw underflow();
	_top-=1;
	return *reinterpret_cast<char*>(var);
}
